package edu.arizona.sista.learn.model;

import java.util.Comparator;

/**
 * A simple model for a duration interval: [start, end).
 * 
 * @author Anh Tran
 *
 */
public class Interval implements Comparable<Interval> {
	
	/**
	 *  Noise model for intervals (in # of frames).
	 */
	public static final int NOISE_WINDOW = 5;
	
	private int _start;
	private int _end;
	
	public Interval(int start, int end) {
		_start = start;
		_end = end;
	}
	
	public int start() {
		return _start;
	}
	
	public void setStart(int start) {
		_start = start;
	}
	
	public int end() {
		return _end;
	}
	
	public void setEnd(int end) {
		_end = end;
	}
	
	/**
	 * Measure duration of [start, end).
	 * @return The duration of [start, end).
	 */
	public int duration() {
		return _end - _start;
	}
	
	/**
	 * Simple test to see if the timestep falls within the interval [start, end).
	 * @param timeStep A step in time.
	 */
	public boolean isOn(int timeStep) {
		return (_start <= timeStep && timeStep < _end);
	}
	
	@Override
	public String toString() {
		return "[" + _start + ", " + _end + ")";
	}
	
	@Override
	public int compareTo(Interval o) {
		return Interval.esf.compare(this, o);
	}

	/**
	 * A generic comparator that will compare two temporal objects in a sortable
	 * fashion. esf --> earliest starting first.
	 */
	public static Comparator<Interval> esf = new Comparator<Interval>() {
		public int compare(Interval o1, Interval o2) {
			if (o1.start() > o2.start())
				return 1;
			if (o1.start() < o2.start())
				return -1;

			if (o1.end() > o2.end())
				return 1;
			if (o1.end() < o2.end())
				return -1;
			
			return 0;
		}
	};
	
	/**
	 * A generic comparator that will compare two temporal objects in a sortable
	 * fashion. eef --> earliest ending first.
	 */
	public static Comparator<Interval> eef = new Comparator<Interval>() {
		public int compare(Interval o1, Interval o2) {
			if (o1.end() > o2.end())
				return 1;
			if (o1.end() < o2.end())
				return -1;

			if (o1.start() > o2.start())
				return 1;
			if (o1.start() < o2.start())
				return -1;

			return 0;
		}
	};

	/**
	 * A generic comparator that will compare two temporal objects in a sortable
	 * fashion. Order by start time and ignore end time completely
	 */
	public static Comparator<Interval> starts = new Comparator<Interval>() {
		public int compare(Interval o1, Interval o2) {
			if (o1.start() > o2.start())
				return 1;
			if (o1.start() < o2.start())
				return -1;
			return 0;
		}
	};

	/**
	 * A generic comparator that will compare two temporal objects in a sortable
	 * fashion. Order by end time and ignore start time completely
	 */
	public static Comparator<Interval> ends = new Comparator<Interval>() {
		public int compare(Interval o1, Interval o2) {
			if (o1.end() > o2.end())
				return 1;
			if (o1.end() < o2.end())
				return -1;
			return 0;
		}
	};
	
	/**
	 * Does this interval overlap with the given interval or does
	 * either interval start within some time period of the other?
	 * @param i
	 * @param window
	 * @return
	 */
	public boolean overlaps(Interval i, int window) {
		if (this.end() + window <= i.start())
			return false;
		if (i.end() + window <= this.start())
			return false;
		return true;
	}
	
	/**
	 * Does this interval overlap or meet the given interval or does
	 * either interval start within some time period of the other?
	 * @param i
	 * @param window
	 * @return
	 */
	public boolean overlapsOrMeets(Interval i, int window) {
		if (this.end() + window < i.start())
			return false;
		if (i.end() + window < this.start())
			return false;
		return true;
	}
	
	/**
	 * Tests whether this time interval starts before and ends after some other time interval.
	 * @param t Time interval.
	 * @param window Noise window.
	 */
	public boolean temporallySubsumes(Interval t, int window) {
		return _start - window <= t.start() && _end + window >= t.end();
	}
	
}
